<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="uaYLB" id="uaYLB"><span data-lake-id="u27594e8e" id="u27594e8e">典型回答</span></h1>
  <p data-lake-id="u17ffd9af" id="u17ffd9af"><span data-lake-id="udc48f5ff" id="udc48f5ff">​</span><br></p>
  <h3 data-lake-id="v3jLW" id="v3jLW"><span data-lake-id="ub0830be8" id="ub0830be8">使用new关键字</span></h3>
  <p data-lake-id="uc2911172" id="uc2911172"><span data-lake-id="ua339302f" id="ua339302f">这是我们最常见的也是最简单的创建对象的方式，通过这种方式我们还可以调用任意的构造函数（无参的和有参的）。 </span></p>
  <p data-lake-id="u168428ab" id="u168428ab"><code data-lake-id="ua9e206c1" id="ua9e206c1"><span data-lake-id="ubd430e9e" id="ubd430e9e">User user = new User();</span></code></p>
  <h3 data-lake-id="igl8D" id="igl8D"><span data-lake-id="u01b58366" id="u01b58366">使用反射机制</span></h3>
  <p data-lake-id="u286def07" id="u286def07"><span data-lake-id="u1ff5de29" id="u1ff5de29">运用反射手段，调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。</span></p>
  <p data-lake-id="u9e044ed0" id="u9e044ed0"><span data-lake-id="u4c51f06b" id="u4c51f06b">1 使用Class类的newInstance方法</span></p>
  <p data-lake-id="u4a55c291" id="u4a55c291"><span data-lake-id="u1b4fb48d" id="u1b4fb48d">可以使用Class类的newInstance方法创建对象。这个newInstance方法调用无参的构造函数创建对象。</span></p>
  <p data-lake-id="u4eedbd44" id="u4eedbd44"><span data-lake-id="u475f4562" id="u475f4562">​</span><br></p>
  <pre lang="java"><code>
User user = (User)Class.forName("xxx.xxx.User").newInstance(); 
User user = User.class.newInstance();
</code></pre>
  <p data-lake-id="u70bebef2" id="u70bebef2"><span data-lake-id="u5aacb5bd" id="u5aacb5bd">​</span><br></p>
  <p data-lake-id="uae4b8aba" id="uae4b8aba"><span data-lake-id="u6431f21a" id="u6431f21a">2 使用Constructor类的newInstance方法</span></p>
  <p data-lake-id="ucda587bc" id="ucda587bc"><span data-lake-id="u72ddd3f1" id="u72ddd3f1">和Class类的newInstance方法很像， java.lang.reflect.Constructor类里也有一个newInstance方法可以创建对象。我们可以通过这个newInstance方法调用有参数的和私有的构造函数。</span></p>
  <pre lang="java"><code>
Constructor  constructor = User.class.getConstructor();
User user = constructor.newInstance();
</code></pre>
  <p data-lake-id="ube8528af" id="ube8528af"><span data-lake-id="u9360bdf2" id="u9360bdf2">​</span><br></p>
  <p data-lake-id="u816a9eee" id="u816a9eee"><span data-lake-id="u6f4e2dc4" id="u6f4e2dc4">这两种newInstance方法就是大家所说的反射。事实上Class的newInstance方法内部调用Constructor的newInstance方法。</span></p>
  <h3 data-lake-id="GvrNl" id="GvrNl"><span data-lake-id="u73026470" id="u73026470">使用clone方法</span></h3>
  <p data-lake-id="u187aba23" id="u187aba23"><span data-lake-id="u8f63923b" id="u8f63923b">无论何时我们调用一个对象的clone方法，jvm就会创建一个新的对象，将前面对象的内容全部拷贝进去。用clone方法创建对象并不会调用任何构造函数。 </span></p>
  <p data-lake-id="u04f97f46" id="u04f97f46"><span data-lake-id="u292fff3d" id="u292fff3d">​</span><br></p>
  <p data-lake-id="u7c4dcee7" id="u7c4dcee7"><span data-lake-id="u7b6cfb13" id="u7b6cfb13">要使用clone方法，我们需要先实现Cloneable接口并实现其定义的clone方法。如果只实现了Cloneable接口，并没有重写clone方法的话，会默认使用Object类中的clone方法，这是一个native的方法。</span></p>
  <pre lang="java"><code>
public class CloneTest implements Cloneable{
    private String name; 
    private int age; 
    public String getName() {
    	return name;
    }
    public void setName(String name) {
    	this.name = name;
    }
    public int getAge() {
    	return age;
    }
    public void setAge(int age) {
    	this.age = age;
    }
    public CloneTest(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public static void main(String[] args) {
        try {
            CloneTest cloneTest = new CloneTest("wangql",18);
            CloneTest copyClone = (CloneTest) cloneTest.clone();
            System.out.println("newclone:"+cloneTest.getName());
            System.out.println("copyClone:"+copyClone.getName());
        } catch (CloneNotSupportedException e) {
        	e.printStackTrace();
        }
    }
}
</code></pre>
  <h3 data-lake-id="Tr0RX" id="Tr0RX"><br></h3>
  <h3 data-lake-id="Dqq7k" id="Dqq7k"><span data-lake-id="ue5e84bcc" id="ue5e84bcc">使用反序列化</span></h3>
  <p data-lake-id="u67a250fc" id="u67a250fc"><span data-lake-id="u86905d57" id="u86905d57">当我们序列化和反序列化一个对象，jvm会给我们创建一个单独的对象。其实反序列化也是基于反射实现的。</span></p>
  <p data-lake-id="u15eacc58" id="u15eacc58"><span data-lake-id="ufb89a130" id="ufb89a130">​</span><br></p>
  <pre lang="java"><code>
public static void main(String[] args) {
    //Initializes The Object
    User1 user = new User1();
    user.setName("hollis");
    user.setAge(23);
    System.out.println(user);

    //Write Obj to File
    ObjectOutputStream oos = null;
    try {
        oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
        oos.writeObject(user);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        IOUtils.closeQuietly(oos);
    }

    //Read Obj from File
    File file = new File("tempFile");
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream(file));
        User1 newUser = (User1) ois.readObject();
        System.out.println(newUser);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        IOUtils.closeQuietly(ois);
        try {
            FileUtils.forceDelete(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
</code></pre>
  <p data-lake-id="ud8cda46b" id="ud8cda46b"><span data-lake-id="ud7afc889" id="ud7afc889">​</span><br></p>
  <p data-lake-id="uf056926b" id="uf056926b"><span data-lake-id="u0a187bfa" id="u0a187bfa">​</span><br></p>
  <h3 data-lake-id="VhUFa" id="VhUFa"><span data-lake-id="ud0cb3ebc" id="ud0cb3ebc">使用方法句柄</span></h3>
  <p data-lake-id="uf55d8005" id="uf55d8005"><br></p>
  <p data-lake-id="u9ac97514" id="u9ac97514"><span data-lake-id="u69e49a9e" id="u69e49a9e">通过使用方法句柄，可以间接地调用构造函数来创建对象</span></p>
  <p data-lake-id="u02c9c7ca" id="u02c9c7ca"><span data-lake-id="ufa950742" id="ufa950742">​</span><br></p>
  <pre lang="java"><code>

public static void main(String[] args) throws Throwable {
    // 定义构造函数的方法句柄类型为void类型，无参数
    MethodType constructorType = MethodType.methodType(void.class);

    // 获取构造函数的方法句柄
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodHandle constructorHandle = lookup.findConstructor(User.class, constructorType);

    // 使用方法句柄调用构造函数创建对象
    User obj = (User) constructorHandle.invoke();
}
</code></pre>
  <p data-lake-id="u4578e9f9" id="u4578e9f9"><br></p>
  <p data-lake-id="u2c5ea163" id="u2c5ea163"><span data-lake-id="u64a93bf4" id="u64a93bf4">使用了MethodHandles.lookup().findConstructor()方法获取构造函数的方法句柄，然后通过invoke()方法调用构造函数来创建对象。</span></p>
  <p data-lake-id="ueedb2991" id="ueedb2991"><br></p>
  <p data-lake-id="uda6e16d8" id="uda6e16d8"><br></p>
  <h3 data-lake-id="l9YCx" id="l9YCx"><span data-lake-id="u05b6359a" id="u05b6359a">使用Unsafe分配内存</span></h3>
  <p data-lake-id="uc4d28b10" id="uc4d28b10"><br></p>
  <p data-lake-id="ue2b9114c" id="ue2b9114c"><span data-lake-id="u7cbe2155" id="u7cbe2155">在Java中，可以使用sun.misc.Unsafe类来进行直接的内存操作，包括内存分配和对象实例化。然而，需要注意的是，sun.misc.Unsafe类是Java的内部API，它并不属于Java标准库的一部分，也不建议直接在生产环境中使用。</span></p>
  <p data-lake-id="uad3ea650" id="uad3ea650"><br></p>
  <pre lang="java"><code>

public static void main(String[] args) throws Exception {

    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    Unsafe unsafe = field.get(null);

    // 获取User类的字段偏移量
    long nameOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("name"));
    long ageOffset = unsafe.objectFieldOffset(User.class.getDeclaredField("age"));

    // 使用allocateInstance方法创建对象，不会调用构造函数
    User user = (User) unsafe.allocateInstance(User.class);

    // 使用putObject方法设置字段的值
    unsafe.putObject(user, nameOffset, "Hollis");
    unsafe.putInt(user, ageOffset, 30);
}


</code></pre>
  <p data-lake-id="ub3fa9c03" id="ub3fa9c03"><br></p>
  <p data-lake-id="u0357bb2c" id="u0357bb2c"><br></p>
  <p data-lake-id="u464a8f4b" id="u464a8f4b"><span data-lake-id="u78ac84b6" id="u78ac84b6">这种方式有以下几个缺点：</span></p>
  <p data-lake-id="u4060ceac" id="u4060ceac"><span data-lake-id="uf7027076" id="uf7027076">​</span><br></p>
  <ol list="u92fc6277">
   <li fid="u3285c4c1" data-lake-id="u169fcaa3" id="u169fcaa3" data-lake-index-type="true"><span data-lake-id="u8b1492d0" id="u8b1492d0">不可移植性：Unsafe类的行为在不同的Java版本和不同的JVM实现中可能会有差异，因此代码在不同的环境下可能会出现不可移植的问题。</span></li>
   <li fid="u3285c4c1" data-lake-id="uefee429b" id="uefee429b" data-lake-index-type="true"><span data-lake-id="u676e241c" id="u676e241c">安全性问题：</span><span data-lake-id="ua2589f40" id="ua2589f40">Unsafe</span><span data-lake-id="u692e623c" id="u692e623c">类的功能是非常强大和危险的，可以绕过Java的安全机制，可能会导致内存泄漏、非法访问、数据损坏等安全问题。</span></li>
   <li fid="u3285c4c1" data-lake-id="u8056736c" id="u8056736c" data-lake-index-type="true"><span data-lake-id="u80a5fc61" id="u80a5fc61">不符合面向对象的原则：Java是一门面向对象的语言，鼓励使用构造函数和工厂方法来创建对象，以确保对象的正确初始化和维护对象的不变性。</span></li>
  </ol>
  <p data-lake-id="ua9b806ee" id="ua9b806ee"><br></p>
 </body>
</html>